from info.module.passport import passport_bp
from flask import Flask, request,current_app,make_response,jsonify,session
from info.utitls.captcha.captcha import captcha
from info import redis_store, constants
from info.utitls.response_code import RET

from info.lib.yuntongxun.sms import CCP
import re
from info.models import User
from info import db
from datetime import datetime


# 退出登录
@passport_bp.route('/login_out', methods=["POST"])
def login_out():
    # 删除ｓｅｓｓｉｏｎ中用户数据即可
    session.pop("user_id", None)
    session.pop("mobile", None)
    session.pop("nick_name", None)
    # 当退出登录的时候需要将管理员的权限记录去掉
    session.pop("is_admin", None)
    return jsonify(errno=RET.OK, errmsg="退出登录成功")


# 2使用蓝图

"""
1,获取get请求中的code_id
2,将code_id根将要发送到前端的验证码保存在redis内存中。
3,逻辑比较，判断用户填写的验证码跟自己保存的验证码是否一致
  3.1,验证一致
  3.2 验证不一致
4,返回给前端。

"""

@passport_bp.route("/image_code")
def hello_world():
    # 1,获取code_id
    code_id = request.args.get("code_id", "")
    # 2,判断code_id 是否有值
    if not code_id:
        current_app.logger.error("参数不足")
        return "请输入验证码"
    # 3 逻辑判断
    image_name, image_code, image_data = captcha.generate_captcha()
    # setes方法，是再redis类里面封装好的，括号里面需要三个参数，key， 时间， 值，
    # constants.IMAGE_CODE_REDIS_EXPIRES  ，是调用constantspy文件中的yige时间
    redis_store.setex("ImageCode_%s"% code_id, constants.IMAGE_CODE_REDIS_EXPIRES, image_code)

    respones = make_response(image_data)
    respones.headers["Content-Type"]= "image/JPEG"
    return   respones

"""
短信发送验证
1,获取数据
   1.1获取用户手机号mobile，用户输入的图片验证码内容image_code，真实的图片的验证码编号image_code_id。
2,校验数据
    2.1查看这三项内容是否为空
        2.2.1mobile的是否为空
        2.2.2image_code是否为空
        2.2.3image_code_id是否还存在
3,逻辑判断
    3.1
4,返回前端


"""
# 127.0.0.1:5000/passport/sms_code
@passport_bp.route('/sms_code', methods=["POST"])
def hello_word():
    # 1,获取参数,这是由前端发送过来的一个请求，被打包成为一个字典。然后从字典中获取这些数据。
    param_dict = request.json
    mobile = param_dict.get("mobile")
    image_code = param_dict.get("image_code")
    image_code_id = param_dict.get("image_code_id")
    # 2,非空判断
    if not all([mobile, image_code, image_code_id]):
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    if not re.match("1[35789][0-9]{9}", mobile):
        current_app.logger.error("手机格式错误")
        return jsonify(errno=RET.PARAMERR, errmsg="手机格式错误")
    try:
    # 3, 通过image_code_id编号，获取真正的image_code

        real_image_code = redis_store.get("ImageCode_%s" %image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询验证码真实值异常")

    # 3.1 如果real_image_code 有值的话，那就删掉他，防止被人重复利用。
    if real_image_code:
        try:
            redis_store.delete("imager_code_id")
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="删除真实验证码的值防止被重复利用")


    else:
        current_app.logger.error("验证码图片过期")
        return jsonify(errno=RET.NODATA, errmsg="验证码图片过期")
    # 3.2 然后进行比对验证。
    # 3.3.1  不相等两个细节，1,验证码大小写，2,验证码的格式
    if image_code.lower() !=real_image_code.lower():
        current_app.logger.error("验证码有误")
        return jsonify(errno=RET.DATAERR, errmsg="填写图片验证码错误")
    # 3.3.2  相等发送短信验证码

    try:
        # 查询手机号码是否已经备注
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户数据异常")
    if user:
        return jsonify(errno=RET.DATAEXIST, errmsg="用户已经注册" )
    # 3.3.3 用户不存在发送短信验证码
    import  random
    # 随机生成一个六位数，不够六位补零

    sms_code = random.randint(0, 99999)
    # 不足六位前面补零06d 六位小数，不够六位前面补零
    sms_code = "%06d" % sms_code
    print(sms_code)
    # 3.3.4 调用封装好的cpp短信验证封装类。
    try:
        result = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES/60], 1)
    except Exception as e:
        return jsonify(errno=RET.THIRDERR, errmsg="短信验证码发送失败" )
    if result == -1:
        current_app.logger.error("短信发送失败")
        return jsonify(errno=RET.THIRDERR, errmsg="短信验证码发送失败")
    # 3.3.5 短信发送成功，
    # 将短信发送的值保存到redis数据库中
    try:
        redis_store.setex("SMS_%s" % mobile, constants.SMS_CODE_REDIS_EXPIRES,  sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据保存失败")

    # 4 返回值
    # 4.1 发送短信验证码成功
    return jsonify(errno=RET.OK, errmsg="发送短信验证码成功")



"""
注册后端实现
１，获取相关参数，mobile, smscode(短信验证码）,password(密码)
２，矫正参数，
    ２．１，判断参数是否为空
    ２．２，正则验证手机号码
3,逻辑判断
    ３．０，获取密码
        ３．０．１，正则判断密码
        ３．０．２查询手机号是否被注册过


    ３．１，再redis 中提取sms_code,
        3.1.1,如果提取到了，然后就删除他，
        ３.1.2 如果没有提取到，验证码过期．
    ３．２　比较real_sms_code 跟输入的值
        ３.2.1,不相等，短信验证码错误，
        3.2.2,相等，




"""


@passport_bp.route("/register", methods=["POST"])
def register():
    # 1,获取参数
    param_dict = request.json
    mobile = param_dict.get("mobile")
    sms_code = param_dict.get("sms_code")
    password = param_dict.get("password")
    # 2,参数校对
    if not all ([mobile, sms_code, password]):
        current_app.logger.error("参数不足")
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")
    if not re.match("1[35789][0-9]{9}", mobile):

        current_app.logger.error("手机号格式不对")
        return jsonify(errno= RET.PARAMERR, errmsg="参数错误")
    # 3,逻辑处理
    # 3.1 ｒｅｄｉｓ中获取真正的验证号码
    try:
        real_sms_code = redis_store.get("SMS_%s" % mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询短信验证码数据异常")
    if real_sms_code:
        redis_store.delete("SMS_%s" % mobile)
    else:
        # 没有值：短信验证码过期了
        current_app.logger.error("短信验证码过期")
        return jsonify(errno=RET.NODATA, errmsg="短信验证码过期")

    # 3.2  不相等　　　那用户短信验证码，跟真实短信验证码进行比较
    if sms_code != real_sms_code:
        current_app.logger.error("验证码不正确")
        return jsonify(errno=RET.DATAERR, errmsg="验证码错误")
    # 　相等　创建数据库对象，并给对应的属性赋值　　
    user = User()
    user.nick_name = mobile
    user.mobile = mobile
    user.password = password
    # 记录最后一次登录时间
    user.last_login = datetime.now()

    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存用户对象异常")

    # 3.3 注册成功，使用ｓｅｓｓｉｏｎ保存用户基本信息
    session["user_id"] = user.id
    session["mobile"] = mobile
    session["nick_name"] = mobile

    return jsonify(errno=RET.OK, errmsg="注册成功")

"""
1, 获取参数
    １．１mobile:手机号码，　ｐａｓｓｗｏｒｄ：密码
２，参数矫正
    ２.1 非空判断
    2.2 手机号码格式判断
３，业务逻辑
    ３.1根据ｍｏｂｉｌｅ查询当前用户是否存在
   　 存在，进行密码比对
　　　不存在，提示注册
    ３．１ｐａｓｓｗｏｒｄ未加密的密码再次加密后
    　不相等，提示密码填写错误
    　相等，记录用户登录信息，修改用户最后一次登录时间
４，返回登录成功



"""
@passport_bp.route('/login', methods=["POST"])
def login():
    # １，获取参数
    param_dict = request.json
    mobile = param_dict.get("mobile")
    password = param_dict.get("password")

    # 2,参数校对
    # 2.0   非空校验
    if not all([mobile, password]):
        current_app.logger.error("参数不足")
        return jsonify(errno=RET.PARAMERR, errmsg= "参数不足" )
    # 2.1 手机格式校验
    if not re.match("1[35789][0-9]{9}", mobile):
        current_app.logger.error("手机格式错误")
        return jsonify(errno=RET.PARAMERR, errmsg="手机格式错误")
    # 3 根据ｍｏｂｉｌｅ查询当前用户是否真实存在
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")
    if not user:
        current_app.logger.error("用户不存在")
        return jsonify(errno=RET.NODATA, errmsg="用户不存在")
    # 3.1 password 未加密，再次进行加密
    # 密码不相等，提示密码填写错误
    # 　user.check_passowrd(password)　底层由封装，返回的是一个布尔值
    if not user.check_passowrd(password):
        return jsonify(errno=RET.DATAERR, errmsg="密码填写错误")
    # 相等记录用户信息，修改用户最后一次登录时间
    session["user_id"] = user.id
    session["mobile"] = mobile
    session["nick_name"] = mobile
    # 修改最后一次登录时间
    user.last_login = datetime.now()
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 数据库回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存用户数据异常")
    return jsonify(errno=RET.OK, errmsg="登录成功")































